﻿using SlimDX;
using SlimDX.Direct3D10;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ColladaLoader
 {
  public class MeshContainer {
    public MeshContainer() {
    }


    #region Optimize vertex buffer
    #region Flip index order
    /// <summary>
    /// Little helper method to flip indices from 0, 1, 2 to 0, 2, 1.
    /// This way we can render with CullClockwiseFace.
    /// </summary>
    private int FlipIndexOrder(int oldIndex)
    {
        int polygonIndex = oldIndex % 3;
        if (polygonIndex == 0)
            return oldIndex;
        else if (polygonIndex == 1)
            return (ushort)(oldIndex + 1);
        else //if (polygonIndex == 2)
            return (ushort)(oldIndex - 1);
    }
    #endregion

    #region OptimizeVertexBuffer
    private ushort[] OptimizeVertexBuffer()
    {
        List<SkinnedTangentVertex> newVertices = new List<SkinnedTangentVertex>();
        List<ushort> newIndices = new List<ushort>();

        // Helper to only search already added newVertices and for checking the
        // old position indices by transforming them into newVertices indices.
        List<int> newVerticesPositions = new List<int>();

        // Go over all vertices (indices are currently 1:1 with the vertices)
        for (int num = 0; num < vertices.Count; num++)
        {
            // Get current vertex
            SkinnedTangentVertex currentVertex = vertices[num];
            bool reusedExistingVertex = false;

            // Find out which position index was used, then we can compare
            // all other vertices that share this position. They will not
            // all be equal, but some of them can be merged.
            int sharedPos = reuseVertexPositions[num];
            foreach (int otherVertexIndex in reverseReuseVertexPositions[sharedPos])
            {
                // Only check the indices that have already been added!
                if (otherVertexIndex != num &&
                    // Make sure we already are that far in our new index list
                  otherVertexIndex < newIndices.Count &&
                    // And make sure this index has been added to newVertices yet!
                  newIndices[otherVertexIndex] < newVertices.Count &&
                    // Then finally compare vertices (this call is slow, but thanks to
                    // all the other optimizations we don't have to call it that often)
                  SkinnedTangentVertex.NearlyEquals(
                  currentVertex, newVertices[newIndices[otherVertexIndex]]))
                {
                    // Reuse the existing vertex, don't add it again, just
                    // add another index for it!
                    newIndices.Add((ushort)newIndices[otherVertexIndex]);
                    reusedExistingVertex = true;
                    break;
                }
            }

            if (reusedExistingVertex == false)
            {
                // Add the currentVertex and set it as the current index
                newIndices.Add((ushort)newVertices.Count);
                newVertices.Add(currentVertex);
            }
        }

        // Finally flip order of all triangles to allow us rendering
        // with CullCounterClockwiseFace (default for XNA) because all the data
        // is in CullClockwiseFace format right now!
        for (int num = 0; num < newIndices.Count / 3; num++)
        {
            ushort swap = newIndices[num * 3 + 1];
            newIndices[num * 3 + 1] = newIndices[num * 3 + 2];
            newIndices[num * 3 + 2] = swap;
        } // for

        vertices = newVertices; //reassign the vertex list with the optimized list

        return newIndices.ToArray();
    }
    #endregion

    #endregion

    #region Generate vertex and index buffers
    /// <summary>
    /// Generate vertex and index buffers
    /// </summary>
    public void GenerateVertexAndIndexBuffers()
    {
        // Optimize vertices first and build index buffer from that
        indices = OptimizeVertexBuffer();

        numOfVertices = vertices.Count;

        if (vertices.Count > ushort.MaxValue)
            throw new InvalidOperationException(
              "Too much vertices to index, optimize vertices or use " +
              "fewer vertices. Vertices=" + vertices.Count +
              ", Max Vertices for Index Buffer=" + ushort.MaxValue);

        numOfIndices = indices.Length;
    }
    #endregion


    /// <summary>
    /// Helpers to remember how we can reuse vertices for OptimizeVertexBuffer.
    /// See below for more details.
    /// </summary>
    public int[] reuseVertexPositions;
    /// <summary>
    /// Reverse reuse vertex positions, this one is even more important because
    /// this way we can get a list of used vertices for a shared vertex pos.
    /// </summary>
    public List<int>[] reverseReuseVertexPositions;



    /// <summary>
    /// Vertices 
    /// </summary>
    public List<SkinnedTangentVertex> vertices = new List<SkinnedTangentVertex>();
    /// <summary>
    /// Indices
    /// </summary>
    public ushort[] indices;

    /// <summary>
    /// Number of triangles 
    /// </summary>
    public int numTriangles;

    /// <summary>
    /// Number of vertices and number of indices we got in the
    /// vertex and index buffers.
    /// </summary>
    public int numOfVertices = 0, numOfIndices = 0;

    /// <summary>
    /// Object matrix for our mesh. Often used to fix mesh to bone skeleton.
    /// </summary>
    public Matrix objectMatrix = Matrix.Identity;
    public Vector3 position;
    public List<string>  textures = new List<string>();
    public List<EffectNode> materials = new List<EffectNode>();

    public String Name;


  }
}
